package com.demo.gateway.sentinel.filter;

import com.demo.gateway.sentinel.api.ConfigClient;
import com.demo.gateway.sentinel.config.DynamicConfig;
import com.demo.gateway.sentinel.config.SysConstatnt;
import com.demo.gateway.sentinel.factory.FlowControlFactory;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.*;

/**
 * 访问控制Filter
 */
@Configuration
@Slf4j
public class AccessFilter implements GlobalFilter, Ordered {

    private final static ExecutorService executorService = new ThreadPoolExecutor(2, 2, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
    @Autowired
    private FlowControlFactory flowControlFactory;
    @Autowired
    private DynamicConfig dynamicConfig;
    @Autowired
    private RedisTemplate redisTemplate;
    @Lazy
    @Autowired
    private ConfigClient configClient;

    @SneakyThrows
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();


        // 模拟通过接口获取配置信息以供限流等使用
        Future<Boolean> data = executorService.submit(()-> configClient.config());
        if(data.get()) {
            return get404Mono(response);
        };
        // 模拟通过限流完成限流
        for (String name : dynamicConfig.getFcName().split(",")) {
            if(flowControlFactory.get(name).control()) {
                return get404Mono(response);
            }
        }
        return chain.filter(exchange.mutate().request(request).build()).then(Mono.fromRunnable( () -> {
            // 处理调用结果，用于判断api质量
            log.info("接口{}调用结果：{}",request.getURI(),response.getStatusCode());
        }));
    }

    private Mono<Void> get404Mono(ServerHttpResponse response) {
        DataBuffer buffer = response.bufferFactory().wrap("已限流".getBytes(StandardCharsets.UTF_8));
        response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
        response.setStatusCode(HttpStatus.FORBIDDEN);
        return response.writeWith(Mono.just(buffer));
    }

    @Override
    public int getOrder() {
        return SysConstatnt.FilterOrder.FILTER_ACCESS;
    }
}
